<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>OpenSteer Preliminary Documentation</title>
  
  <style type="text/css">
  .graybox    { vertical-align: top;
                padding: 2px 8px 2px 8px;
                color: black;
                background-color: #e0e0e0; }
  .boxVM      { vertical-align: middle;
                padding: 0 0 0 0;
                color: black;
                background-color: white; }
  .boxVMxxx   { vertical-align: middle;
                padding: 0 0 0 0;
                color: black;
                background-color: yellow; }
  .boxVT      { vertical-align: top;
                padding: 0 0 0 0;
                color: black;
                background-color: white;}
  .sourcecode { font-family: monospace; }
  .nowrap     { white-space: nowrap; }
  body        { color: black;
                background-color: white; }
  </style>
  <link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon"></head>

<body>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
  <tbody>
    <tr>
      <td class="boxVT" align="left"> <b><big><big><big><big>OpenSteer</big></big><br>
Documentation </big></big></b> <br>
      </td>
      <td class="boxVM" align="right"> <a href="index.html"><br>
      </a> </td>
    </tr>
    <tr>
      <td style="vertical-align: top;"><small><br>
November 11, 2004<BR>
revised June 15, 2007 for SVN<br>
revised Feb 12, 2019 for git<BR>
      <small>Version 0.8.3</small></small></td>
      <td style="vertical-align: top; text-align: right;"><a href="index.html">
        <img src="images/beta_250a.gif" alt="OpenSteer Logo" border="0" height="250" width="250"></a></td>
    </tr>
    <tr>
      <td style="vertical-align: top;"> by <br>
      <a href="http://www.red3d.com/cwr/">Craig Reynolds</a> <br>
      <a href="http://www.research.scea.com/">Research and Development</a>
      <br>
      <a href="http://www.scea.com/">Sony Computer Entertainment America</a></td>
      <td style="vertical-align: top;"><br>
      </td>
    </tr>
  </tbody>
</table>
<br>
<br>
<br>
<br>
<br>
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%">
  <tbody>
    <tr>
      <td class="graybox"> <big><big> <b><br>
      <a name="TableofContents"></a>Table of Contents </b></big> </big><br>
      <a href="#Introduction">Introduction</a> <br>
      <a href="#WetPaint">Wet Paint</a> <br>
      <a href="#UsingOpenSteerDemo">Using OpenSteerDemo</a> <br>
      <a href="#SamplePlugIns">Sample PlugIns</a> <br>
      <a href="#WritingPlugIns">Writing PlugIns</a> <br>
      <a href="#SteeringLibrary">Steering Library</a> <br>
      <a href="#Integrating">Integrating with Your Code</a> <br>
      <a href="#InstallingOpenSteer">Installing OpenSteer</a> <br>
      <a href="#KnownBugs">Known Bugs and Missing Features</a> <br>
      <a href="#RelatedLinks">Related Links</a> <br>
      <br>
      </td>
    </tr>
  </tbody>
</table>
<br>
<br>
<br>
<big>
<big><b><br>
<a name="Introduction"></a>
Introduction
</b></big></big>
<p><b>OpenSteer</b> is an open source library of components to help
build <a href="http://www.red3d.com/cwr/steer/">steering behaviors</a>
for autonomous characters in games and other kinds of multi-agent
simulations. These agents may represent characters (humans, animals,
alien creatures), vehicles (cars, planes, spaceships) or other kinds
of mobile agents. OpenSteer was originally developed on Linux and
was subsequently ported to Windows and Mac OS X.</p>
<p>OpenSteer provides a toolkit of steering behaviors, defined in
terms of an abstract mobile agent called a <em>vehicle. </em>Sample
code
is provided, including a simple vehicle implementation and examples of
combining simple steering behaviors to produce more complex
behavior. In order to allow flexible integration with existing game
engines OpenSteer can add its functionality by either layering or
inheritance. <small><a href="#Integrating">[see "Integrating with Your
Code" below]</a></small> Note that OpenSteer is intended for use by
programmers. It does not plug into interactive production tools, nor
does it support behavior authoring by non-programmers.</p>
<p>In addition to the library, OpenSteer provides an
interactive application called <b>OpenSteerDemo</b> which initially
demonstrates several steering behaviors. OpenSteerDemo can also help
you
create novel steering behaviors, providing facilities to visualize,
annotate and debug your code. OpenSteerDemo is written in C++ and uses
OpenGL
graphics. All OpenGL calls are segregated in one module, in case you
need to substitute another graphics API.
</p>
<p>OpenSteerDemo is based on a <em>plug-in</em> architecture: an empty
framework into which plug-ins can be added incrementally. OpenSteerDemo
comes with several sample plug-ins.
<small><a href="#SamplePlugIns">[see "Sample PlugIns"
below]</a></small> You can easily create your own plug-ins by starting
from these examples. A OpenSteerDemo plug-in specifies several generic
actions required by the OpenSteerDemo framework: open, close, reset,
run
one simulation step, display one frame, and so on. The plug-in defines
vehicle classes and manages them in simulation. It defines scene
geometry in terms of obstacles, pathways and so on. Plug-ins control
the camera and handle Function Keys.</p>
<p>OpenSteerDemo's plug-in framework allows a game AI programmer to
quickly prototype behaviors during game design, and to develop
behaviors before the main game engine is finished. In OpenSteer 0.8.3,
OpenSteerDemo allows the user to interactively control simulation time
(stop, start, single step), select the vehicle/character/agent of
interest, and adjust the
view and tracking behavior of the camera.</p>
<p>OpenSteer is distributed as open source software in accordance with
the <a href="http://www.opensource.org/licenses/mit-license.php">MIT
License</a>.</p>
<big>
<big><b><br>
<a name="WetPaint"></a>
Wet Paint!
</b></big></big>
<p>Warning: OpenSteer 0.8.3 is still under active development. It is
not mature or stable. Its current design is subject to change and
reorganization, although every attempt will be made to avoid
gratuitous changes. We welcome your interest in OpenSteer and
encourage experimentation. However please <a href="contact.html">contact
us</a> before planning to integrate
OpenSteer into any large project.</p>
<p>Note also that the term <em>plug-in</em> is currently misused here.
Normally it implies that a new module can be added to an application
at <b>run</b> time. Whereas in OpenSteer 0.8.3 the "plugging-in" must
happen at application <b>build</b> (link) time. One would hope this
was fixed in a future release (he said, hoping to avoid specific
promises of future enhancements).</p>
<big>
<big><b><br>
<a name="UsingOpenSteerDemo"></a>
Using OpenSteerDemo
</b></big></big>
<p>After installation <small><a href="#InstallingOpenSteer">[see
"Installing OpenSteer" below]</a></small> launch the OpenSteerDemo
application. <small>(On Linux, Mac or Windows you can do this by
double clicking on a desktop icon. If you have downloaded the
OpenSteer source code and compiled it yourself, you can also launch the
application from your IDE build tools. If you use the supplied
Makefile for Linux, you can execute the <span style="font-weight: bold;">make run</span> command.)</small> When you
first use OpenSteerDemo, this <a href="stref.html">quick
reference guide</a> may be helpful. The application will open a
single window labeled "OpenSteerDemo 0.8.". You should see a
diagrammatic 3d
view of the default PlugIn. Typically you will see moving vehicles,
annotation graphics and textual overlays, as shown in <small><a href="#Figure1">[Figure 1]</a></small>.</p>
<a name="Figure1"></a>
<div align="center"><img src="images/typical_SteerTest.png" alt="typical OpenSteerDemo window" height="558" width="673"><br>
<br>
Figure 1: typical OpenSteerDemo window
<br>
</div>
<p>Eventually OpenSteerDemo may have a menu-based graphical user
interface. For now it supports limited mouse-based interaction
(camera view adjustment, vehicle selection) and recognizes several
single key commands:</p>
<table align="center" border="0" cellpadding="0" cellspacing="3" width="90%">
  <tbody>
    <tr>
      <td class="graybox" width="25%">Tab</td>
      <td class="graybox">select next PlugIn</td>
    </tr>
    <tr>
      <td class="graybox">r</td>
      <td class="graybox">restart current PlugIn</td>
    </tr>
    <tr>
      <td class="graybox">s</td>
      <td class="graybox">select next vehicle/agent/character&nbsp; (or
mouse-click to select)</td>
    </tr>
    <tr>
      <td class="graybox">c</td>
      <td class="graybox">select next camera aiming mode</td>
    </tr>
    <tr>
      <td class="graybox">f</td>
      <td class="graybox">select next preset frame rate&nbsp;
(as-fast-as-possible, 24fps, 60fps)</td>
    </tr>
    <tr>
      <td class="graybox">a</td>
      <td class="graybox">toggle annotation on/off</td>
    </tr>
    <tr>
      <td class="graybox">Space</td>
      <td class="graybox">toggle between Run and Pause</td>
    </tr>
    <tr>
      <td class="graybox">-&gt; &nbsp; (right arrow)</td>
      <td class="graybox">step forward one frame</td>
    </tr>
    <tr>
      <td class="graybox">?</td>
      <td class="graybox">print "mini help" on console&nbsp; (or see
the <a href="stref.html">quick reference guide</a>)</td>
    </tr>
    <tr>
      <td class="graybox">Esc</td>
      <td class="graybox">exit OpenSteerDemo</td>
    </tr>
  </tbody>
</table>
<p>In addition a PlugIn can provide handlers for the Function
Keys (labeled F1 through F12 on most keyboards). Type a <span style="font-weight: bold;">?</span> to print a list of all recognized
commands, including those handled
by the current PlugIn. (There is an issue with printing <small><a href="KnownBugs">[see "Known Bugs" below]</a></small>.)<br>
</p>
<p>OpenSteerDemo keeps track of a single <em>selected</em> agent which
the
camera follows. In some demos additional annotation is provided for
the selected agent. The user can change selection with the mouse.
Pointing the mouse near an agent will cause it to highlight (for
example, in the provided 2d demos, a gray disk is drawn under it).
Clicking the (left) mouse button selects the highlighted agent.
OpenSteerDemo's camera (<em>point of view</em>) adjusts itself
automatically
to keep the selected vehicle in view. Several different camera aiming
modes are provided:</p>
<table align="center" border="0" cellpadding="0" cellspacing="3" width="90%">
  <tbody>
    <tr>
      <td class="graybox" width="25%">static</td>
      <td class="graybox">fixed camera</td>
    </tr>
    <tr>
      <td class="graybox">fixed&nbsp;distance&nbsp;offset</td>
      <td class="graybox">camera remains a fixed distance from selected
vehicle </td>
    </tr>
    <tr>
      <td class="graybox">fixed local offset</td>
      <td class="graybox">camera remains fixed in selected vehicle's
local space </td>
    </tr>
    <tr>
      <td class="graybox">straight down</td>
      <td class="graybox">camera looks at selected vehicle from
directly above </td>
    </tr>
    <tr>
      <td class="graybox">offset POV</td>
      <td class="graybox">camera looks in selected vehicle's forward
direction, from a given
offset in the vehicle's local space </td>
    </tr>
  </tbody>
</table>
<p>You can adjust the camera's view with the mouse (or whatever input
device you use). OpenSteerDemo lets you adjust the camera's <em>position
</em>relative to its <em>aimpoint. </em>The aimpoint is defined by
camera
aiming mode and is normally the (predicted future position of the)
selected vehicle. To adjust the camera: hold down the keyboard's
<em>control </em>(Ctrl) key while dragging the mouse with its left
button held down. 2D mouse motion is mapped into the camera's space,
rotating the camera's position around its aimpoint. This allows the
camera to move on the surface of a sphere centered at the aimpoint.
The radius of this sphere--the "viewing distance"--can be adjusted by
dragging the mouse with the middle button held down (vertical mouse
motion maps to distance). If you use a one- or two-button mouse
(hence no middle button) you can adjust the radius by holding down
both the Ctrl and Alt ("control-meta-") keys while dragging the mouse
with its left button held down. Note that adjustments in "offset POV"
camera aiming mode actually translate rather than rotate the camera
position relative to the selected vehicle.</p>
<p>To preserve a stable view, OpenSteerDemo's camera will smoothly
interpolate over changes due to: motion of the selected vehicle,
mouse-based camera adjustment, or switching camera aiming modes.
</p>
<p>OpenSteerDemo's clock provides two time streams: <em>real
time </em>and
<em>simulation time</em>. The redraw cycle and camera update are based
on passage of real time. Simulation time normally follows real time
but can also be <em>paused</em>, freezing simulation of vehicle motion.
Pausing the simulation often helps to allow examining annotation in
detail, or to interactively reposition the camera. (In the current
implementation: when simulation time is paused, simulation updates
continue to happen each frame, but the <em>elapsed time </em>("dt") is
given as zero.) The clock can be set to run in one of three modes
described in the table below. You can use OpenSteerDemo's
<b>&nbsp;f&nbsp;</b> keyboard command to cycle among several
preset combinations of clock mode and target frame rate. Your
PlugIn code can also set these modes using Clock methods:<span class="sourcecode">
get/setFixedFrameRate, get/setAnimationMode,
get/setVariableFrameRateMode, get/set/togglePausedState.</span> For
more detail, see <b>Clock.h</b></p>
<table align="center" border="0" cellpadding="0" cellspacing="3" width="90%">
  <tbody>
    <tr>
      <td class="graybox" width="25%">variable frame rate</td>
      <td class="graybox">For viewing real-time simulations. Updates
run as
fast as possible. Simulation time steps are set equal to the amount of
real time elapsed since the previous update. Similar to graphics
on a PC.<br>
      </td>
    </tr>
    <tr>
      <td class="graybox">fixed target frame rate</td>
      <td class="graybox"> For viewing real-time simulations. Updates
are
constrained to occur at multiples of a fixed frame rate (often 30 or 60
fps) by waiting until the next fame boundary. If the update
takes too long, it has to wait for the second frame boundary (aka <span style="font-style: italic;">frame out</span> or <span style="font-style: italic;">double
framing</span>). Similar to graphics on a video game console. </td>
    </tr>
    <tr>
      <td class="graybox">animation mode<br>
      </td>
      <td class="graybox">For running fixed time step simulations,
generally <span style="font-style: italic;">not</span> in real-time,
which may
appear to run in "slow motion". Ignores real time to produce
consistent simulation results.<br>
      </td>
    </tr>
  </tbody>
</table>
<p>OpenSteerDemo aims to support a developer's work by providing tools
and
utilities that while helpful, might not be critical enough to justify
writing them during a production schedule. This includes various API
for drawing annotation using elements such as lines, vectors, boxes,
circles, disks, spheres and text attached to the screen or positions
in 3d space. A facility is provided for drawing <em>streamers/trails
</em>which display a vehicle's recent motion then fade away. There are
utilities for drawing a ground plane and highlighting vehicles in
various ways. See <b>Annotation.h</b> and <b>OpenSteerDemo.h</b> for
details. You can turn annotation on and off with OpenSteerDemo's <b>&nbsp;a&nbsp;</b>
command.</p>
<p>
<big><big><b><br>
<a name="SamplePlugIns"></a>
Sample PlugIns
</b></big></big></p>
OpenSteerDemo is distributed with several PlugIns intended to serve
both
as demonstrations of steering behaviors, and as sample code: jumping
off places for you to begin developing your own steering behaviors.
The current list of sample PlugIns are:
<p><b>Capture the Flag:</b> a single (bluish) attacker attempts to
reach a central goal while four (reddish) defenders try to intercept
("tag") the attacker before it gets to the goal. The playing field is
optionally littered with obstacles. This benchmark was proposed by
Marcin Chady of the Working Group on Steering of the IGDA's AI
Interface Standards Committee. The obstacles are spheres, depicted by
their equator. Press F1 to add an obstacle (up to 100 of them), F2 to
remove one. The "game" ends when the attacker reaches the goal or a
defender tags the attacker. The demo automatically restarts a few
seconds later. The attacker combines three basic steering behaviors:
<em>goal seeking</em>, <em>evasion</em> and <em>obstacle avoidance</em>.
The defenders combine <em>pursuit</em> and <em>obstacle avoidance</em>. A
key to "non-stupid" behavior by the attacker was to notice when there
is a defender-free "corridor" between it and the goal. When found,
this corridor is depicted by a green outline. In this case the
attacker uses pure <em>seek</em> and stops evading nearby defenders.
The pursuit behavior of the defenders needed to specialized so that
they "knew" not to predict the motion of the attacker past its goal.
The defenders do not otherwise think about global strategy, for
example they don't try to place themselves between the attacker and
the goal. Currently defenders ignore each other, they probably should
separate or avoid collisions with each other, ideally they would
coordinate their pursuit. The attacker is easily confused when
several defenders converge from different directions. Obstacles are
always avoided by going toward the nearer edge, as discussed in the
Steering Working Group's forum, this is frequently the "wrong"
direction when considering the agent's other goals. I want to revisit
this later.</p>
<p><span style="font-weight: bold;">MapDrive:</span> path-following
through map-based obstacles using curvature-based prediction and
steering. This demonstration is inspired by the <a href="http://www.darpa.mil/grandchallenge/">DARPA Grand Challenge</a>
cross country race for autonomous vehicles.
A route is defined as a series of (GPS) waypoints and a width
associated with each segment between waypoints. This demo assumes
sensors on-board the vehicle create a binary map classifying the
surrounding terrain into <span style="font-style: italic;">drivable</span>
and <span style="font-style: italic;">not drivable</span>. The vehicle
tries
to follow the route while avoiding obstacles and maximizing speed. When
the vehicle finds itself in danger of collision, it "gives up" (turns
yellow) and slows to a stop. If it collides with an obstacle it turns
red. In both cases the simulation is restarted. (This plug-in includes
two non-path-following demos of map-based obstacle avoidance. Use F1 to
select among them.)&nbsp;
</p>
<p><b>Pedestrians:</b> 100 agents follow a path (the red line) and try
not to collide with each other or two large spherical obstacles.
Press F1 to add a Pedestrian and F2 to remove one. This multiagent
simulation uses a spatial database to accelerate proximity queries, F3
cycles among types of proximity databases (two exist in OpenSteer
0.8.3). F4 toggles between two versions of path following: <span style="font-style: italic;">stay on the
path </span>and <span style="font-style: italic;">directed path
following.</span> The latter means to stay on
the path while moving along it in a given direction. A Pedestrian's
direction is
reversed when reaches the end of the path. Press F5 to toggle a
Pedestrian's <span style="font-style: italic;">wander
</span>component on and off.</p>
<p><b>Boids:</b> 200 simulated flocking <a href="http://www.red3d.com/cwr/boids/">bird like objects</a>. The
boids model is a simple combination of <em>separation, alignment
</em>and <em>cohesion </em>steering behaviors. Press F1 to add a Boid
and F2 to remove one. This multiagent simulation uses a spatial
database to accelerate proximity queries, F3
cycles among types of proximity databases (two exist in OpenSteer
0.8.3). The flock flies within a sphere, F4 toggles between two
boundary
conditions. One is "steer back when outside" -- when a boid
travels
outside the sphere it begins to <em>seek</em>
towards the center. The other is "wrap around (teleport)" --
boids that fly out of the sphere are instantly repositioned to the
opposite side of the sphere.<br>
</p>
<p><span style="font-weight: bold;">Soccer:</span> this simulation of a
simple soccer game was contributed by Michael Holm of <a href="http://www2.ioi.dk/">IO Interactive</a> on July 9, 2003.
It consists of a blue and red team of 8 Players each, a green Ball and
an <span style="font-style: italic;">axis aligned bounding box</span>
class (AABBox) used to represent the field and the two goals. As
play proceeds the PlugIn keeps score. The ball is derived from
SimpleVehicle but its vehicle-like motion is replaced by bounce
physics. Michael invites others to contribute improved Player
designs. <br>
</p>
<p><b>Multiple Pursuit:</b> a "test fixture" for the <em>pursue</em>
behavior. 30 pursuers chase one wandering quarry. The colored lines
indicate the predicted future position of the quarry being used as a
<em>seek</em> target by each pursuer. The colors indicate which of nine
prediction cases is active. When a pursuer reaches the quarry it is
"teleported" away to a random position.</p>
<p><b>Low Speed Turn:</b> a "test fixture" for evaluating the response
of a vehicle to backward-pointing steering force while moving at low
speed.</p>
<p><b>One Turning Away:</b> this was the first one, now it serves as a
minimal example of a PlugIn.</p>
<p>
<big><big><b><br>
<a name="WritingPlugIns"></a>
Writing PlugIns
</b></big></big></p>
Developing interesting, lifelike steering behaviors is an unique
type of programming. It mixes the mathematical and algorithmic rigor
of computer programming with a more artistic, aesthetic-based phase of
parameter tweaking. OpenSteer is intended to allow you to focus on
developing steering behaviors without having to worry about all of the
required framework. This is supported through OpenSteerDemo's PlugIn
mechanism. When you write a PlugIn, you need to provide only the code
that is specific to your own vehicles and their steering behaviors.
<p>Currently the best source of detailed information on the PlugIn
interface is in the C++ header file <b>PlugIn.h</b>. See particularly
the commented-out meta-example called<span class="sourcecode">
FooPlugIn. </span>That header file defines two classes:<span class="sourcecode"> AbstractPlugIn </span>(a pure virtual interface
class) and<span class="sourcecode"> PlugIn </span>which provides the
base implementation. To create a new OpenSteerDemo PlugIn, you will
define a new class which inherits the base implementation from<span class="sourcecode"> PlugIn. </span>It provides some default methods
(see
<b>PlugIn.h</b> for details) which you can overload to customize,
particularly<span class="sourcecode"> reset</span>. You must implement
six methods on your new class to fulfill the<span class="sourcecode">
AbstractPlugIn </span>protocol:</p>
<table align="center" border="0" cellpadding="0" cellspacing="3" width="90%">
  <tbody>
    <tr>
      <td class="graybox" width="25%"><span class="sourcecode">name</span></td>
      <td class="graybox">returns a character string name</td>
    </tr>
    <tr>
      <td class="graybox"><span class="sourcecode">open</span></td>
      <td class="graybox">allocate and initialize vehicles</td>
    </tr>
    <tr>
      <td class="graybox"><span class="sourcecode">close</span></td>
      <td class="graybox">deallocate</td>
    </tr>
    <tr>
      <td class="graybox"><span class="sourcecode">update</span></td>
      <td class="graybox">perform one stimulation step</td>
    </tr>
    <tr>
      <td class="graybox"><span class="sourcecode">redraw</span></td>
      <td class="graybox">do all graphics for one frame</td>
    </tr>
    <tr>
      <td class="graybox"><span class="sourcecode">allVehicles</span></td>
      <td class="graybox">return a group of all this PlugIn's vehicles</td>
    </tr>
  </tbody>
</table>
<p>For a minimal working PlugIn see "One Turning Away"
(<b>opensteer/plugins/OneTurning.cpp</b>) which defines a single
vehicle with trivial behavior. LowSpeedTurn also has trivial behavior
and features multiple vehicles, Boids has many vehicles,
MultiplePursuit has two kinds of vehicles, Pedestrian and
CaptureTheFlag are more complicated samples.</p>
<p>Probably the easiest way to get started on your own PlugIn is: (1)
pick one of the samples that seems most closely related (2) make a
renamed copy of it (3) build OpenSteerDemo (4) verify that the new
PlugIn
appears and has its old behavior (5) make
incremental
changes to the working PlugIn to create your own behavior. If you are
using an IDE (an Integrated Development Environment such as <a href="http://www.apple.com/macosx/features/xcode/">Xcode</a> or <a href="http://msdn.microsoft.com/vstudio/">Visual Studio</a>) you will
have to add your new PlugIn's source file to your IDE <span style="font-style: italic;">project</span> (probably by adding it as a
component to the OpenSteerDemo build target). On Linux using <a href="http://www.gnu.org/software/make/">make</a> (or <a href="http://www.kdevelop.org/">KDevelop</a>), if you leave your
PlugIn's source file in the standard directory (<b>opensteer/plugins/</b>)
will be compiled automatically. (Ideally compiling a PlugIn
should not require compiling OpenSteerDemo <small><a href="#KnownBugs">[see
"Known Bugs" below]</a></small>.)</p>
<p>The samples in <b>opensteer/plugins/</b> each define at least one
new vehicle class and one new PlugIn class. A key requirement is that
a single instance of the new PlugIn class be statically allocated, as
in:</p>
<blockquote> <span class="sourcecode">// define a new Vehicle<br>
class OneTurning : public SimpleVehicle {...}<br>
  <br>
// define a new PlugIn<br>
class OneTurningPlugIn : public PlugIn {...}<br>
  <br>
// instantiate the PlugIn<br>
  <b>OneTurningPlugIn gOneTurningPlugIn;</b> </span></blockquote>
<p>The name of that global (<span class="sourcecode">gOneTurningPlugIn</span>)
is irrelevant, what
matters is that a single instance of the new PlugIn class (<span class="sourcecode">OneTurningPlugIn</span>) is allocated for the
lifetime of the OpenSteerDemo application. The actual "plugging in" is
handled by the constructor(/destructor) of the<span class="sourcecode">
PlugIn</span> base class. A class which is intended to be
instantiated exactly once is sometimes called a <em>singleton</em>.
PlugIns expect to be instantiated exactly once but do not enforce or
detect violations of that policy. Because PlugIns register
themselves, the samples are defined in <b>.cpp</b> files and there is
no need for <b>.h</b> files. You may wish to organize your PlugIn
differently, perhaps with a <b>.h</b> file or perhaps including one
for a class of vehicle defined elsewhere.</p>
<p>Normally your PlugIn will define one or more classes of Vehicle.
OpenSteer tries to provide a lot of flexibility in how this can be
done. On the other hand, if you are just trying to get your first
experiment running under OpenSteerDemo, you probably want what Devo
called
"freedom <em>from </em>choice." The easiest approach, and what all the
provided samples do, is to define a new vehicle class as a
specialization of<span class="sourcecode"> SimpleVehicle. </span>In
general, all that is required to make use of the OpenSteer steering
library is to support the<span class="sourcecode">
AbstractVehicle</span> protocol in whatever manner you see fit.</p>
<p>OpenSteerDemo and the provided PlugIns make use of two types defined
in<span class="sourcecode"> AbstractVehicle: AbstractVehicle::group
</span>and<span class="sourcecode"> AbstractVehicle::iterator</span>.
These are<span class="sourcecode"> typedef</span>ed to the names<span class="sourcecode"> AVGroup </span>and<span class="sourcecode">
AVIterator. AVGroup</span> is used whenever a group of<span class="sourcecode"> AbstractVehicle</span>s need to be remembered or
passed as a function argument.<span class="sourcecode">
AVIterator </span>is used to iterate over the contents of an<span class="sourcecode"> AVGroup. </span>These types are based on the C++
STL
(Standard Template Library) parameterized types<span class="sourcecode">
vector </span>and<span class="sourcecode"> const_iterator. AVGroup
</span>and<span class="sourcecode"> AVIterator </span>are used inside
the OpenSteer library, but if you wish to avoid using STL it should be
easy to replace them with your own implementation of collections and
iteration.</p>
<p>Random notes for PlugIn writers:
</p>
<ul>
  <li>
    <p>Time values are currently passed as float values, measured in
seconds. Perhaps there should be a more specific typedef for time.</p>
  </li>
  <li>
    <p><span class="sourcecode">Vec3 </span>is the type used
throughout
OpenSteer to represent geometric vectors in 3d Cartesian space.
Colors are currently represented as <span class="sourcecode">Vec3</span>s.
Perhaps there should be a
more
specific typedef for color.</p>
  </li>
  <li>
    <p>One way to help debug or analyze your steering behaviors is to
pick one vehicle and provide additional information about it, using
graphical annotation or printed output. A convenient choice is
OpenSteerDemo's <span style="font-style: italic;">selected vehicle: </span>the
one the camera normally follows and which can be changed with a mouse
click (or the OpenSteerDemo <b>&nbsp;s&nbsp;</b> command). To trigger
code
specifically for the selected vehicle, use something like this in your
vehicle's update method:&nbsp;&nbsp; <span class="sourcecode">if&nbsp;(this&nbsp;==&nbsp;OpenSteerDemo::selectedVehicle)&nbsp;{...}</span>
    </p>
  </li>
</ul>
<p>
<big><big><b><br>
<a name="SteeringLibrary"></a>
Steering Library
</b></big></big></p>
<p><em>Note: this section is preliminary and subject to change. The
documentation could conceivably be out of sync with the library itself.
For the Real Truth always consult the source code.</em></p>
<p>In current organization of OpenSteer, its main library of steering
behaviors is contained in the class SteerLibraryMixin (defined in
<b>SteerLibrary.h</b>). A mixin is a class with templated superclass
-- it is used to add a set of methods to a given base class.
<small><a href="#Integrating">[see "Integrating with Your Code"
below]</a></small> In this case, SteerLibraryMixin adds steering
functionality to a class which supports the AbstractVehicle interface.
For example, SimpleVehicle combines SteerLibraryMixin and several
other utilities with AbstractVehicle. As a result, SimpleVehicle has
all of the methods defined in SteerLibraryMixin, which are listed
below.</p>
<p>Note that several of the steering behaviors will return a zero
vector value (0, 0, 0) to indicate "no steering is required at this
time" typically because a goal is already met. The caller can detect
these cases by testing to see if
the returned steering value is equal to zero:&nbsp;&nbsp;
<span class="sourcecode">if&nbsp;(steering&nbsp;==&nbsp;Vec3::zero)&nbsp;...</span></p>
<b>Wander behavior</b>
<br>
<blockquote>
  <pre>Vec3 steerForWander (float dt);<br></pre>
  <p>Returns a steering force for wandering behavior. The steering
value is purely tangential (has no Forward component). The time step
value allows wander rate to be consistent when frame times vary.</p>
</blockquote>
<b>Seek behavior</b>
<br>
<blockquote>
  <pre>Vec3 steerForSeek (const Vec3&amp; target);<br></pre>
  <p>Returns a steering force to seek the given target location. Causes
a vehicle to turn toward the target and move to it. If this behavior
is used alone and unconditionally, it will cause the vehicle to pass
through the target then turn around for another pass.</p>
</blockquote>
<b>Flee behavior</b>
<br>
<blockquote>
  <pre>Vec3 steerForFlee (const Vec3&amp; target);<br></pre>
  <p>Returns a steering force to flee from the given target location.
Causes a vehicle to turn away from the target and move away from it
it.</p>
</blockquote>
<b>Path Following behavior</b>
<br>
<blockquote>
  <pre>Vec3 steerToFollowPath (const int direction,<br>                        const float predictionTime,<br>                        Pathway&amp; path)<br><br>Vec3 steerToStayOnPath (const float predictionTime, Pathway&amp; path)<br></pre>
  <p>Returns a steering force to follow a given path. <span class="sourcecode">steerToStayOnPath</span> just tries to keep the
vehicle on the path. <span class="sourcecode">steerToFollowPath</span>
provides <span style="font-style: italic;">directed path following </span>where
the vehicle both stays on the path and heads in a given direction along
the path, as indicated by the <span class="sourcecode">direction</span>
argument which should be either +1 or -1. The path
defines a <em>tube </em>in terms of a <em>spine </em>and a <em>radius </em>,
the goal is to keep a vehicle headed toward a point inside that tube.
(OpenSteer 0.8.3 provides one kind of Path with a polyline spine:
a
series of connected line segments (see <span style="font-weight: bold;">Pathway.h</span>)
and a prototype of another kind of path called GCRoute is defined in
the MapDrive PlugIn.)
Steering is determined based on a prediction of the vehicle's
position<span class="sourcecode"> predictionTime </span>seconds into
the
future. If that predicted position is inside the pathway (and in the
case of directed path following, is headed in the correct direction)
this
function returns a zero vector value. Otherwise it steers toward
a point on the path.<br>
  </p>
</blockquote>
<b>Obstacle Avoidance behavior</b>
<br>
<blockquote>
  <pre>Vec3 steerToAvoidObstacle (const float minTimeToCollision,<br>                           const Obstacle&amp; obstacle);<br><br>Vec3 steerToAvoidObstacles (const float minTimeToCollision,<br>                            const ObstacleGroup&amp; obstacles)</pre>
  <p>Returns a steering force to avoid given obstacles. The obstacles
can be specified as either a single Obstacle or as a
ObstacleGroup (an STL Vector of Obstacle pointers). The purely
lateral steering force will turn our vehicle towards a silhouette edge
of the obstacle. Avoidance is required when (1) the obstacle
intersects the vehicle's current path, and (2) it is in front of the
vehicle, and (3) is within<span class="sourcecode"> minTimeToCollision </span>seconds
of travel at the vehicle's current velocity. If multiple Obstacles were
specified, and multiple potential collisions exist, the nearest (most
urgent) one is chosen. When no
avoidance is required this function returns a zero vector value.
Note that the older <span class="sourcecode">steerToAvoidObstacle</span>
calling sequence may be changed or removed in the future.<br>
  </p>
</blockquote>
<b>Unaligned Collision Avoidance behavior</b>
<br>
<blockquote>
  <pre>Vec3 steerToAvoidNeighbors (const float minTimeToCollision,<br>                            const AVGroup&amp; others);<br></pre>
  <p>Returns a steering force to avoid colliding with other nearby
vehicles moving in unconstrained directions. Determine which (if any)
other other vehicle we would collide with first, then steers to avoid
the site of that potential collision. (The current (2D) version only
steers laterally, it does not speed up or slow down, as described in
the <a href="http://www.red3d.com/cwr/papers/1999/gdc99steer.html">GDC
1999 paper</a>.) Returns a steering force vector of zero length if
there is no impending collision.</p>
</blockquote>
<b>Separation behavior</b>
<br>
<blockquote>
  <pre>Vec3 steerForSeparation (const float maxDistance,<br>                         const float cosMaxAngle,<br>                         const AVGroup&amp; flock);<br></pre>
  <p>Returns a steering force to move us away from nearby boids.</p>
</blockquote>
<b>Alignment behavior</b>
<br>
<blockquote>
  <pre>Vec3 steerForAlignment (const float maxDistance,<br>                        const float cosMaxAngle,<br>                        const AVGroup&amp; flock);<br></pre>
  <p>Returns a steering force to align us with nearby boids.</p>
</blockquote>
<b>Cohesion behavior</b>
<br>
<blockquote>
  <pre>Vec3 steerForCohesion (const float maxDistance,<br>                       const float cosMaxAngle,<br>                       const AVGroup&amp; flock);<br></pre>
  <p>Returns a steering force to move us towards the "center of mass"
of
nearby boids.</p>
</blockquote>
<b>Pursuit behavior</b>
<br>
<blockquote>
  <pre>Vec3 steerForPursuit (const AbstractVehicle&amp; quarry);<br><br>Vec3 steerForPursuit (const AbstractVehicle&amp; quarry,<br>                      const float maxPredictionTime);<br></pre>
  <p>Returns a steering force to pursue another moving vehicle. Heads
towards the predicted point of interception. An alternate version is
provided to specify a ceiling on the prediction interval: aim for
where the quarry will be in (say) 5 seconds, or the point of
interception, whichever happens sooner.</p>
</blockquote>
<b>Evasion behavior</b>
<br>
<blockquote>
  <pre>Vec3 steerForEvasion (const AbstractVehicle&amp; menace,<br>                      const float maxPredictionTime);<br></pre>
  <p>Returns a steering force to evade another moving vehicle. Heads
away from the predicted point of interception.</p>
</blockquote>
<b>Speed Maintenance behavior</b>
<br>
<blockquote>
  <pre>Vec3 steerForTargetSpeed (const float targetSpeed);<br></pre>
  <p>Returns a steering force to maintain a given target speed. The
value will be along the vehicle's forward/backward axis and its length
will be clipped to the vehicle's maxForce parameter.</p>
</blockquote>
<p><b>Annotation "hooks"</b>
<br>
</p>
<blockquote>These "do nothing" methods are defined by
SteerLibraryMixin. They are called when various steering
behaviors decide to take action. These <span style="font-style: italic;">hook</span> methods are intended to be
overloaded
by
PlugIn writers to provide graphical annotation, or other side
effects. For
example the Pedestrian vehicle class overloads<span class="sourcecode">
annotateAvoidObstacle </span>to draw annotation lines around the
vehicle's obstacle avoidance corridor when an obstacle is found inside
of it.
  <pre>// Called when steerToAvoidObstacles decides steering is required.<br>virtual void annotateAvoidObstacle (const float minDistanceToCollision);<br><br>// Called when steerToFollowPath decides steering is required.<br>virtual void annotatePathFollowing (const Vec3&amp; future,<br>                                    const Vec3&amp; onPath,<br>                                    const Vec3&amp; target,<br>                                    const float outside);<br><br>// Called when steerToAvoidCloseNeighbors decides steering is required.<br>virtual void annotateAvoidCloseNeighbor (const AbstractVehicle&amp; other,<br>                                         const float additionalDistance);<br><br>// Called when steerToAvoidNeighbors decides steering is required.<br>virtual void annotateAvoidNeighbor (const AbstractVehicle&amp; threat,<br>                                    const float steer,<br>                                    const Vec3&amp; ourFuture,<br>                                    const Vec3&amp; threatFuture);<br></pre>
</blockquote>
<br>
<p><big><big><b><a name="Integrating"></a>
Integrating with Your Code
</b></big></big></p>
<p><em>Note: this section is so preliminary that it is really just a
placeholder...</em></p>
<p>This section will eventually talk about the structure of
OpenSteer's classes, and how they are designed to provide you with
flexibility as you integrate OpenSteer with your existing code. It
will mention that if you were writing new code, you could always base
your classes on OpenSteer's. More typically you will already have an
existing code base, a game engine or a procedural animation system,
into which you want to integrate some of OpenSteer's facilities.</p>
<p>OpenSteer's classes have been designed to allow you freedom to
either inherit its functionality, or to layer its functionality on top
of your existing classes. The latter approach is supported by the
concept of <a href="http://citeseer.nj.nec.com/smaragdakis00mixinbased.html">
mixin classes</a> (essentially a class with templated superclass)
which allows its functionality to be "mixed in with" (or "layered on
top of") your existing classes. A similar effect can be obtained by
multiple inheritance of your preexisting base classes and OpenSteer's
classes, but most C++ programmers prefer to avoid multiple
inheritance. Many of OpenSteer's classes are defined in three parts:
an abstract protocol (aka interface or pure virtual class:
"AbstractLocalSpace"), an implementation expressed as a mixin
("LocalSpaceMixin") and an instantiable class made by layering the
mixin on top of the abstract protocol ("LocalSpace"). For more detail
see <b>LocalSpace.h</b> and the discussion at the top of
<b>SimpleVehicle.h</b></p>
<p>Finally OpenSteer anticipates that it may be used in class
hierarchies based on either the IS-A or the HAS-A architecture. That
is, you might want an agent in your game to be structured so that it
IS-A OpenSteer Vehicle or you may want to structure it so that it HAS-A
Vehicle as a component part. (But no sample of using an OpenSteer
Vehicle in a HAS-A architecture is provided <small><a href="KnownBugs">[see
"Known Bugs" below]</a></small>.)</p>
<p>
<big><big><b><br>
<a name="InstallingOpenSteer"></a>
Installing OpenSteer
</b></big></big></p>
OpenSteer can be used several ways. The OpenSteer software can be obtained by
downloading and building from the github repository: <a href="https://github.com/meshula/OpenSteer">(link)</a>.
<p>Previous versions of OpenSteer are available at the original repository on 
  sourceforge. 
<a href="http://sourceforge.net/svn/?group_id=77546">(link)</a>
<p>To build OpenSteer's library and application you will need version 3.10 or
  later of cmake. The repository contains all needed dependencies, so building
should only require running cmake in the usual way with your generator of choice.</p>
<P>OpenSteer is currently tested on macos, windows, and ubuntu.</P>
<p><big><big><b><br>
<a name="KnownBugs"></a>Known Bugs and Missing Features
</b></big></big></p>
<ul>
  <li>
    <p>In OpenSteerDemo, it seems like you ought to be able to use the
mouse to interactively adjust position and orientation of the vehicles.
But you can't. Other things you can't do include interactively creating
new instances of a PlugIn's vehicle types, or deleting old ones. As
anyone who has tried it knows, the hardest part of creating interesting
life-like behaviors is tuning the parameters. It sure would be nice if
OpenSteerDemo provided mouse-driven sliders ("valuators") PlugIns could
call to interactively adjust behavioral parameters.</p>
  </li>
  <li>
    <p>Some of the behaviors detailed in the <a href="http://www.red3d.com/cwr/papers/1999/gdc99steer.html">1999
paper</a> have not been implemented yet in OpenSteer. They are:
offset pursuit, arrival, wall following, containment, flow field
following, and leader following. Also unimplemented are behaviors
which the paper mentioned in passing: explore, forage, interpose,
shadow, docking, hide. Eventually OpenSteer should provide all of
them.</p>
  </li>
  <li>
    <p>When avoiding obstacles it looks much more sensible, efficient
and lifelike if the vehicle steers toward the nearer edge of a looming
obstacle. But obstacle avoidance is blended with other behaviors (say
with evasion, as in the Capture the Flag PlugIn) this will often steer
the vehicle into a strategically bad position. Much better to go the
"long way" around an obstacle than to go directly in to the path of
your opponent. Perhaps obstacle avoidance should take an argument
representing the steering that would be used in the absence of an
obstacle. This can be used to bias the choice of a path around the
obstacle. There is an underlying suggestion that effective blending of
behaviors cannot be cleanly separated from the behaviors themselves.
(See also <a href="http://citeseer.org/benamor03fast.html">Fast, Neat
and Under Control: Inverse Steering Behaviors for Physical Autonomous
Agents</a>.)<br>
    </p>
  </li>
  <li>
    <p> Currently the Pedestrians always move forward at full speed and
try to avoid collisions purely by turning. They should be improved so
they modulate both their heading <span style="font-weight: bold;">and</span>
their speed, coming to a stop if necessary to avoid a collision.</p>
  </li>
  <li>
    <p>As can be seen occasionally in the Capture the Flag PlugIn, when
obstacle avoidance steering behavior fails to prevent collisions
(intersection of vehicle and obstacle) the obstacle avoidance behavior
appears to give up: it ignores the obstacle and steers right through it.</p>
  </li>
  <li>Boids should have a preference for level flight, perhaps as a
user-selectable option. Right now they are as likely to fly straight up
and horizontally.<br>
  </li>
  <li>
    <p>One ought to be able to add a PlugIn to OpenSteerDemo at
runtime. <small>[<a href="https://sourceforge.net/forum/message.php?msg_id=2788973">forum
thread</a>]<br>
    </small></p>
  </li>
  <li>
    <p>Non-penetration constraints should be supported in OpenSteer so
vehicles can be prevented from intersecting obstacles and other
vehicles.</p>
  </li>
  <li>
    <p>Current demos use either 2d vehicles on the plane or 3d vehicles
in space. Opensteer should provide support for 2d vehicles on
non-planar surfaces.</p>
  </li>
  <li>
    <p>When OpenSteerDemo is launched from the desktop (say by
double-clicking on an icon) printed messages may
be lost, or at
least not be seen immediately by the user. <small>[<a href="http://sourceforge.net/forum/message.php?msg_id=2801351">forum
thread</a>]</small><br>
    </p>
  </li>
  <li>
    <p>Many of OpenSteer's component APIs (such as: Clock, Annotation
and SimpleVehicle) are not documented beyond cryptic comments in header
files. It has been <a href="http://sourceforge.net/forum/message.php?msg_id=2698066">suggested</a>
that perhaps OpenSteer should use comments compatible with the <a href="http://www.stack.nl/%7Edimitri/doxygen/">Doxygen</a> system for
generating API docs.<br>
    </p>
  </li>
  <li>
    <p>Stupidly, the various <span style="font-style: italic;">annotation</span>
(deferred graphics) types
(lines, circles) are currently limited to a fixed number of
objects. OpenSteerDemo incessantly prints complaints when these limits
are exceeded.<br>
    </p>
  </li>
  <li>
    <p>There should be sample code (in a PlugIn) showing how to use
OpenSteer in a more traditional, non-mixin, HAS-A architecture. <small>[<a href="https://sourceforge.net/forum/message.php?msg_id=2799598">forum
thread</a>]</small><br>
    </p>
  </li>
</ul>
<!-- -----------------------------------------------------------------

<big>
<big>
<b>
Miscellaneous Notes:
</b>
</big>
</big>

<p><b>Time</b> is measured in seconds since the simulation was begun,
and represented as a floating point number.  (XXX which begs the
question, should OpenSteer define a "time" type? XXX)</p>

----------------------------------------------------------------- --><big><big>
<b><br>
<a name="RelatedLinks"></a>
Related Links:
</b></big></big><small>&nbsp;&nbsp;
(Please feel free to <a href="contact.html">suggest</a> new links for
this section)
</small>
<ul>
  <li>
    <p><a href="index.html">OpenSteer</a> on the web at <a href="http://www.sourceforge.net/">SourceForge.Net</a></p>
  </li>
  <li>
    <p><a href="http://www.red3d.com/cwr/papers/1999/gdc99steer.html">Steering
Behaviors For Autonomous Characters</a> the GDC 1999 paper on steering
behaviors, and this companion page with <a href="http://www.red3d.com/cwr/steer/">background, updates and </a><a href="http://www.red3d.com/cwr/steer/">Java demos</a>.</p>
  </li>
  <li> <a href="http://www.igda.org/ai/ai_committee.php">AI Interface
Standards Committee</a> of the <a href="http://www.igda.org/">IGDA</a>
which includes a Steering Working Group</li>
  <li>
    <p>Systems that use OpenSteer:</p>
    <ul>
      <li>
        <p><a href="http://www.cs.ubc.ca/%7Ebforsyth/research/">Intelligent
Support of Interactive Manual Control: Haptic Guidance Based on a
Look-Ahead Predictor</a> by <a href="http://www.cs.ubc.ca/%7Ebforsyth/">Ben
Forsyth</a> .&nbsp; In his Master's thesis, Ben used OpenSteer as a
framework for his experiments, used path following behavior in a novel
application, and invented a new and more realistic model of a steerable
wheeled vehicle.</p>
      </li>
      <li>
        <p><a href="http://pizzagame.sourceforge.net/">Pizza Game</a></p>
      </li>
      <li><a href="http://tmema.org/messa/messa.html">Messa di Voce</a><br>
      </li>
    </ul>
  </li>
  <li>
    <p>Systems similar to OpenSteer <small>(see also this <a href="http://cs.gmu.edu/%7Eeclab/projects/mason/#Other">list of
related simulators</a>)</small>:</p>
    <ul>
      <li>
        <p><a href="http://www.spiderland.org/breve/">breve</a>: a 3d
Simulation Environment for Decentralized Simulations and Artificial Life</p>
      </li>
      <li>
        <p><a href="http://cs.gmu.edu/%7Eeclab/projects/mason/">MASON</a>
is a fast discrete-event multiagent simulation library core in
Java.&nbsp; <br>
        </p>
      </li>
      <li><a href="http://crowd.webhop.org/">Crowd Simulation Framework</a>
based on steering behaviors</li>
      <li>
        <p><a href="http://www.codeproject.com/useritems/metaagent.asp">MetaAgent</a>,
a Steering Behavior Template Library (<a href="http://metaagent.sourceforge.net/">see also</a>).</p>
      </li>
      <li>
        <p><a href="http://dec.bournemouth.ac.uk/staff/jmacey/msc/msc.html">Emergent
Behaviour Programming Language E.B.P.L.</a> (2003) by <a href="http://dec.bournemouth.ac.uk/staff/jmacey/">Jonathan Macey</a>
describes a specialized language for programming multi-agent
simulations.</p>
      </li>
    </ul>
  </li>
  <li>
    <p>Sample applications of steering behaviors (pre-OpenSteer): </p>
    <ul>
      <li>
        <p><a href="http://www.red3d.com/cwr/papers/2000/pip.html">Interaction
with Groups of Autonomous Characters</a> (2000) describes a interactive
system featuring large group of characters based on steering behaviors,
includes a video.</p>
      </li>
      <li>
        <p><a href="http://www.research.scea.com/oldsite/sig01/sig01_procedural.htm">Video
Game Play and Design: Procedural Directions</a> (2001) includes video
of the Stuart/Bird/Fish demo with a skinned articulated 3d character
driven by steering behaviors.</p>
      </li>
    </ul>
  </li>
  <li>
    <p><a href="http://sourceforge.net/forum/message.php?msg_id=2721305">Steering,
planning and learning</a>, a forum thread on advanced steering
architectures which cites several recent publications.<br>
    </p>
  </li>
  <li>
    <p>Online resources on computational geometry: </p>
    <ul>
      <li>
        <p><a href="http://www.magic-software.com/">Magic Software
by David Eberly</a></p>
      </li>
      <li>
        <p><a href="http://astronomy.swin.edu.au/%7Epbourke/geometry/">Geometry</a>
by <a href="http://astronomy.swin.edu.au/%7Epbourke/">Paul Bourke</a></p>
      </li>
      <li>
        <p><a href="http://www.ics.uci.edu/%7Eeppstein/geom.html">Geometry
in Action</a> by <a href="http://www.ics.uci.edu/%7Eeppstein/">David
Eppstein</a></p>
      </li>
      <li>
        <p><a href="http://compgeom.cs.uiuc.edu/%7Ejeffe/compgeom/code.html">Computational
Geometry Code</a> by <a href="http://compgeom.cs.uiuc.edu/%7Ejeffe/index.html">Jeff Erickson</a></p>
      </li>
    </ul>
  </li>
</ul>
<br>
<hr>
<br>
<p>Please feel free to <a href="contact.html">contact us</a> with
comments or suggestions.
<br>
<br>
<!-- CHANGE DATE AT TOP OF FILE TOO -->Last update: November 11, 2004 <br>
</p>
<a href="http://sourceforge.net">
<img src="http://sourceforge.net/sflogo.php?group_id=77546&amp;type=1" alt="SourceForge.net Logo" border="0" height="31" width="88"></a> <br>
<br>
<a href="index.html">
<img src="images/beta_90a.gif" alt="OpenSteer Logo" border="0" height="90" width="90"></a>
</body></html>